package math

import (
	"jvm/instructions/base"
	"jvm/rtda"
	. "jvm/typedef"
	"math"
)

// 取栈顶元素做运算，结果放回栈顶(无操作数)
// IINC指令是例外 将本地变量表索引位置的int型变量加上指定值后存回该索引位置
// 指令码后一个字节是索引，再后一个字节是要加的值
// *****************************************************************
// int型取余数
// 栈顶元素为除数
// 次栈顶元素为被除数
// a / b   a为被除数，b为除数
type IREM struct {
	base.NoOperandsInst
}

func (self *IREM) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	if v2 == 0 {
		panic("java.lang.ArithmeticException: / by zero")
	}
	result := v1 % v2
	stack.PushInt(result)
}

// *****************************************************************
// long型取余数
// 栈顶元素为除数
// 次栈顶元素为被除数
// a / b   a为被除数，b为除数
type LREM struct {
	base.NoOperandsInst
}

func (self *LREM) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopLong()
	v1 := stack.PopLong()
	if v2 == 0 {
		panic("java.lang.ArithmeticException: / by zero")
	}
	result := v1 % v2
	stack.PushLong(result)
}

// *****************************************************************
// float型取余数
// 栈顶元素为除数
// 次栈顶元素为被除数
// a / b   a为被除数，b为除数
type FREM struct {
	base.NoOperandsInst
}

func (self *FREM) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopFloat()
	v1 := stack.PopFloat()
	result := math.Mod(float64(v1), float64(v2))
	stack.PushFloat(F4(result))
}

// *****************************************************************
// double型取余数
// 栈顶元素为除数
// 次栈顶元素为被除数
// a / b   a为被除数，b为除数
type DREM struct {
	base.NoOperandsInst
}

func (self *DREM) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopDouble()
	v1 := stack.PopDouble()
	result := math.Mod(float64(v1), float64(v2))
	stack.PushDouble(F8(result))
}

// *****************************************************************
// int型左移运算
// 栈顶第一个数为左移的位数
// 栈顶第二个数为被左移的数
type ISHL struct {
	base.NoOperandsInst
}

func (self *ISHL) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	s := U4(v2) & 0x1f
	result := v1 << s
	stack.PushInt(result)
}

// *****************************************************************
// 算术右移
type ISHR struct {
	base.NoOperandsInst
}

func (self *ISHR) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	s := U4(v2) & 0x1f
	result := v1 >> s
	stack.PushInt(result)
}

// *****************************************************************
// 逻辑右移
type IUSHR struct {
	base.NoOperandsInst
}

func (self *IUSHR) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	s := U4(v2) & 0x1f
	num := U4(v1)
	result := num >> s
	stack.PushInt(I4(result))
}

// *****************************************************************
// 左移
type LSHL struct {
	base.NoOperandsInst
}

func (self *LSHL) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := U4(v2) & 0x3f
	result := v1 << s
	stack.PushLong(result)
}

// *****************************************************************
// 算术右移
type LSHR struct {
	base.NoOperandsInst
}

func (self *LSHR) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := U4(v2) & 0x3f
	result := v1 >> s
	stack.PushLong(result)
}

// *****************************************************************
// 逻辑右移
type LUSHR struct {
	base.NoOperandsInst
}

func (self *LUSHR) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopLong()
	s := U4(v2) & 0x3f
	result := (U8(v1)) >> s
	stack.PushLong(I8(result))
}

// *****************************************************************
// int型按位与
type IAND struct {
	base.NoOperandsInst
}

func (self *IAND) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	result := v1 & v2
	stack.PushInt(result)
}

// *****************************************************************
// long型按位与
type LAND struct {
	base.NoOperandsInst
}

func (self *LAND) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopLong()
	v1 := stack.PopLong()
	result := v1 & v2
	stack.PushLong(result)
}

// *****************************************************************
// int型按位或
type IOR struct {
	base.NoOperandsInst
}

func (self *IOR) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	result := v1 | v2
	stack.PushInt(result)
}

// *****************************************************************
// long型按位或
type LOR struct {
	base.NoOperandsInst
}

func (self *LOR) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopLong()
	v1 := stack.PopLong()
	result := v1 | v2
	stack.PushLong(result)
}

// *****************************************************************
// int型按位异或
type IXOR struct {
	base.NoOperandsInst
}

func (self *IXOR) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	result := v1 ^ v2
	stack.PushInt(result)
}

// *****************************************************************
// long型按位异或
type LXOR struct {
	base.NoOperandsInst
}

func (self *LXOR) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopLong()
	v1 := stack.PopLong()
	result := v1 ^ v2
	stack.PushLong(result)
}

// *****************************************************************
type IINC struct {
	Index U2
	Val   I4
}

func (self *IINC) ReadOperands(reader *base.CodeReader) {
	self.Index = U2(reader.ReadU1())
	self.Val = I4(reader.ReadI1())
}

func (self *IINC) Execute(frame *rtda.Frame) {
	localVars := frame.LocalVars()
	v1 := localVars.GetInt(self.Index)
	result := v1 + self.Val
	localVars.SetInt(self.Index, result)

}

// *****************************************************************
// 加
type IADD struct {
	base.NoOperandsInst
}

func (self *IADD) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	result := v1 + v2
	stack.PushInt(result)
}

// *****************************************************************
type LADD struct {
	base.NoOperandsInst
}

func (self *LADD) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopLong()
	v1 := stack.PopLong()
	result := v1 + v2
	stack.PushLong(result)
}

// *****************************************************************
// 加
type FADD struct {
	base.NoOperandsInst
}

func (self *FADD) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopFloat()
	v1 := stack.PopFloat()
	result := v1 + v2
	stack.PushFloat(result)
}

// *****************************************************************
// 加
type DADD struct {
	base.NoOperandsInst
}

func (self *DADD) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopDouble()
	v1 := stack.PopDouble()
	result := v1 + v2
	stack.PushDouble(result)
}

// *****************************************************************
// 减
type ISUB struct {
	base.NoOperandsInst
}

func (self *ISUB) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	result := v1 - v2
	stack.PushInt(result)
}

// *****************************************************************
type LSUB struct {
	base.NoOperandsInst
}

func (self *LSUB) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopLong()
	v1 := stack.PopLong()
	result := v1 - v2
	stack.PushLong(result)
}

// *****************************************************************
type FSUB struct {
	base.NoOperandsInst
}

func (self *FSUB) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopFloat()
	v1 := stack.PopFloat()
	result := v1 - v2
	stack.PushFloat(result)
}

// *****************************************************************
type DSUB struct {
	base.NoOperandsInst
}

func (self *DSUB) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopDouble()
	v1 := stack.PopDouble()
	result := v1 - v2
	stack.PushDouble(result)
}

// *****************************************************************
// 乘
type IMUL struct {
	base.NoOperandsInst
}

func (self *IMUL) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	result := v1 * v2
	stack.PushInt(result)
}

// *****************************************************************
type LMUL struct {
	base.NoOperandsInst
}

func (self *LMUL) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopLong()
	v1 := stack.PopLong()
	result := v1 * v2
	stack.PushLong(result)
}

// *****************************************************************
type FMUL struct {
	base.NoOperandsInst
}

func (self *FMUL) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopFloat()
	v1 := stack.PopFloat()
	result := v1 * v2
	stack.PushFloat(result)
}

// *****************************************************************
type DMUL struct {
	base.NoOperandsInst
}

func (self *DMUL) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopDouble()
	v1 := stack.PopDouble()
	result := v1 * v2
	stack.PushDouble(result)
}

// *****************************************************************
// 除
type IDIV struct {
	base.NoOperandsInst
}

func (self *IDIV) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopInt()
	v1 := stack.PopInt()
	if v2 == 0 {
		panic("java.lang.ArithmeticException: / by zero")
	}
	result := v1 / v2
	stack.PushInt(result)
}

// *****************************************************************
type LDIV struct {
	base.NoOperandsInst
}

func (self *LDIV) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopLong()
	v1 := stack.PopLong()
	if v2 == 0 {
		panic("java.lang.ArithmeticException: / by zero")
	}
	result := v1 / v2
	stack.PushLong(result)
}

// *****************************************************************
type FDIV struct {
	base.NoOperandsInst
}

func (self *FDIV) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopFloat()
	v1 := stack.PopFloat()
	result := v1 / v2
	stack.PushFloat(result)
}

// *****************************************************************
type DDIV struct {
	base.NoOperandsInst
}

func (self *DDIV) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	v2 := stack.PopDouble()
	v1 := stack.PopDouble()
	result := v1 / v2
	stack.PushDouble(result)
}

// *****************************************************************
// 取负
type INEG struct {
	base.NoOperandsInst
}

func (self *INEG) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopInt()
	stack.PushInt(-val)
}

// *****************************************************************
type LNEG struct {
	base.NoOperandsInst
}

func (self *LNEG) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopLong()
	stack.PushLong(-val)
}

// *****************************************************************
type FNEG struct {
	base.NoOperandsInst
}

func (self *FNEG) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopFloat()
	stack.PushFloat(-val)
}

// *****************************************************************
type DNEG struct {
	base.NoOperandsInst
}

func (self *DNEG) Execute(frame *rtda.Frame) {
	stack := frame.OPStack()
	val := stack.PopDouble()
	stack.PushDouble(-val)
}
